<template>
  <div :class="[`${classPrefix}`]" :style="expandStyle">
    <slot></slot>
  </div>
</template>

<script>
import Config from "/src/config";
import Vue from "vue";
const isServer = Vue.prototype.$isServer;
const Popper = isServer
  ? function () {}
  : require("popper.js/dist/umd/popper.js");

export default {
  name: "Drop",
  props: {
    dropdownMatchSelectWidth: Boolean,
    minWidth: {
      type: [Boolean, Number],
      default: true,
    },
    placement: {
      type: String,
      default: "bottom-start",
    },
    reference: {}, // 触发元素
    popper: {},
    value: {
      type: Boolean,
      default: false,
    },
    options: {
      type: Object,
      default: function () {
        return {
          modifiers: {
            computeStyle: {
              gpuAcceleration: false,
            },
            preventOverflow: {
              boundariesElement: "window",
            },
          },
        };
      },
    },
    renderHtml: {
      type: [HTMLElement, Boolean],
      default: function () {
        return false;
      },
    },
  },
  data() {
    return {
      classPrefix: Config.classPrefix + "-drop",
      visible: false,
      width: "",
      boundariesElement: null,
    };
  },
  watch: {
    value: function (newVal) {
      this.visible = newVal;
    },
    visible: function (newVal) {
      if (newVal) {
        this.$nextTick(this.updatePopper());
        this.$emit("on-show");
      } else {
        this.$emit("on-hide");
      }
      this.$emit("input", newVal);
    },
  },
  computed: {
    expandStyle() {
      let style = { width: "auto" };
      if (this.dropdownMatchSelectWidth) style = { width: this.width };
      if (this.minWidth === true) style = { ...style, minWidth: this.width };
      if (this.minWidth !== true && this.minWidth)
        style = { ...style, minWidth: parseInt(this.minWidth) + "px" };
      return style;
    },
  },
  mounted() {
    this.visible = this.value;
    this.$nextTick(() => {
      this.setWidth();
      this.renderToHtml();
    });
  },
  methods: {
    setWidth() {
      const width =
        this.$parent && this.$parent.$el && (this.$parent.$el.offsetWidth || 0);
      this.width = width + "px";
    },
    createPopper() {
      if (isServer) return;
      if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.placement)) {
        return;
      }

      const options = this.options;
      const clPopper = this.$el;
      const reference = this.reference || this.$parent.$refs.reference;

      if (!clPopper || !reference) return;

      if (this.popperJS && this.popperJS.hasOwnProperty("destroy")) {
        this.popperJS.destroy();
      }
      options.placement = this.placement;
      !options.modifiers.offset && (options.modifiers.offset = {});
      options.onCreate = () => {
        this.$nextTick(() => this.updatePopper());
      };

      this.popperJS = new Popper(reference, clPopper, options);
    },
    updatePopper() {
      if (isServer) return;
      this.$nextTick(() => {
        this.setWidth();
      });
      this.popperJS
        ? this.popperJS.update()
        : this.$nextTick(this.createPopper());
    },
    renderToHtml() {
      if (
        (typeof this.renderHtml === "boolean" && this.renderHtml === false) ||
        !this.renderHtml
      )
        return;
      if (typeof this.renderHtml === "boolean" && this.renderHtml === true) {
        document.body.appendChild(this.$el);
      } else {
        this.renderHtml.appendChild(this.$el);
      }
    },
  },
  updated() {
    this.$nextTick(() => {
      this.updatePopper();
    });
  },
  destroyed() {
    if (isServer) return;
    if (this.popperJS && this.popperJS.hasOwnProperty("destroy")) {
      this.popperJS.destroy();
    }
  },
};
</script>
